﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace StockInfoFacade.Utils
{

    #region helper classes, alternative names for string basically
    public class PivotKey
    {
        private readonly String _pvKey;

        public PivotKey(String pvkey)
        {
            _pvKey = pvkey;
        }

        public int Compare(PivotKey a, PivotKey b)
        {
            if (a._pvKey != null && b._pvKey != null) 
            // ReSharper disable once StringCompareIsCultureSpecific.1
                return String.Compare(a._pvKey, b._pvKey);
            else
                return 0;

        }

        public static bool operator ==(PivotKey a, PivotKey b)
        {
            return a._pvKey == b._pvKey;
        }
        public static bool operator !=(PivotKey a, PivotKey b)
        {
            return a._pvKey != b._pvKey;
        }

        public override bool Equals(object obj)
        {
            //if (_pvKey.Equals(obj.ToString()))
            //    Console.WriteLine(obj.ToString());
            return _pvKey.Equals(obj.ToString());
        }

        public override int GetHashCode()
        {
            return _pvKey.GetHashCode();
        }

        public override string ToString()
        {
            return _pvKey;
        }
    }
    public class RowPivotKey : PivotKey
    {
        public RowPivotKey(string pvkey) : base(pvkey)
        {

        }

        public static RowPivotKey Create(string ss)
        {
            return new RowPivotKey(ss);
        }
    }
    public class ColPivotKey : PivotKey
    {
        public ColPivotKey(string pvkey) : base(pvkey)
        {

        }
        public static ColPivotKey Create(string ss)
        {
            return new ColPivotKey(ss);
        }

    }
    #endregion

    public class PivotFunctions
    {

        public static Dictionary<TKey1, Dictionary<TKey2, TValue>>  Pivot3<TSource, TKey1, TKey2, TValue>
            (IEnumerable<TSource> source
            , Func<TSource, TKey1> key1Selector
            , Func<TSource, TKey2> key2Selector
            , Func<IEnumerable<TSource>, TValue> aggregate)
        {
            return source.GroupBy(key1Selector).Select(
                x => new
                {
                    X = x.Key,
                    Y = source.GroupBy(key2Selector).Select(
                        z => new
                        {
                            Z = z.Key,
                            V = aggregate(from item in source
                                          where key1Selector(item).Equals(x.Key)
                                          && key2Selector(item).Equals(z.Key)
                                          select item
                            )

                        }
                    ).ToDictionary(e => e.Z, o => o.V)
                }
            ).ToDictionary(e => e.X, o => o.Y);
        }


        public static Dictionary<TKey1, TValue> PivotGroupOne<TSource, TKey1, TValue>
         (IEnumerable<TSource> source
         , Func<TSource, TKey1> key1Selector
         , Func<IEnumerable<TSource>, TValue> aggregate)
        {
            var v = source.GroupBy(key1Selector).Select(
                z => new
                {
                    Z = z.Key,
                    V = aggregate(from item in source
                                  where key1Selector(item).Equals(z.Key)
                                  select item)

                }).ToDictionary(e => e.Z, o => o.V);

            return v;
        }


        public static List<List<object>> Transform<TKey, TValue>(Dictionary<TKey, Dictionary<TKey, TValue>> source)
        {
            List<List<object>> ret = new List<List<object>>();

            // add column headers
            List<TKey> lstKeys = source.Values.ToList().First().Keys.ToList();
            List<object> lstObjects = lstKeys.ConvertAll(new Converter<TKey, object>(TKeyToObject));
            lstObjects.Insert(0, null);
            lstObjects.Add("C1"); // indicate column header level 1
            ret.Add(lstObjects);

            // add row headers
            source.Values.ToList().ForEach((elem) =>
            {
                var lstV = elem.Values.ToList();
                var lstVObj = lstV.ConvertAll(new Converter<TValue, object>(TKeyToObject));
                lstVObj.Insert(0, "placeholder");
                ret.Add(lstVObj);
            });

            int i = 1;
            source.Keys.ToList().ForEach((elem) =>
            {
                ret[i][0] = elem;
                i++;
            });
            ret[0][0] ="R1";
            return ret;

        }
        private static object TKeyToObject<TKey> (TKey ko)
        {
            return (object) ko;
        }


        #region Testing
        internal class Employee
        {
            public string Name { get; set; }
            public string Department { get; set; }
            public string Function { get; set; }
            public decimal Salary { get; set; }
        }


        public Dictionary<string, Dictionary<string, int>> TestLinqExtenions()
        {
            var l = new List<Employee>() {
    new Employee() { Name = "Fons", Department = "R&D", Function = "Trainer", Salary = 2000 },
    new Employee() { Name = "Jim", Department = "R&D", Function = "Trainer", Salary = 3000 },
    new Employee() { Name = "Ellen", Department = "Dev", Function = "Developer", Salary = 4000 },
    new Employee() { Name = "Mike", Department = "Dev", Function = "Consultant", Salary = 5000 },
    new Employee() { Name = "Jack", Department = "R&D", Function = "Developer", Salary = 6000 },
    new Employee() { Name = "James", Department = "Support", Function = "Admin", Salary = 1000 },
    new Employee() { Name = "Kate", Department = "Management", Function = "VP", Salary = 10000 },
    new Employee() { Name = "Demy", Department = "Dev", Function = "Consultant", Salary = 2000 }};

            return PivotFunctions.Pivot3(l,emp => emp.Department, emp2 => emp2.Function, lst => Convert.ToInt32( lst.Sum(emp => emp.Salary)));
            //return PivotFunctions.Pivot3(l, emp => emp.Function, emp2 => emp2.Department, lst => lst.Count());
        }

        #endregion Testing

    }
}

